package tiled.core;

import java.awt.Rectangle;
import java.util.*;

public class MultilayerPlane implements Iterable<MapLayer>
{
    private Vector<MapLayer> layers;
    protected Rectangle bounds;

    public MultilayerPlane()
    {
        layers = new Vector<MapLayer>();
        bounds = new Rectangle();
    }

    public MultilayerPlane(int width, int height)
    {
        this();
        bounds.width = width;
        bounds.height = height;
    }

    public int getTotalLayers()
    {
        return layers.size();
    }

    public void fitBoundsToLayers()
    {
        int width = 0;
        int height = 0;

        Rectangle layerBounds = new Rectangle();

        for (int i = 0; i < layers.size(); i++)
        {
            getLayer(i).getBounds(layerBounds);
            if (width < layerBounds.width) width = layerBounds.width;
            if (height < layerBounds.height) height = layerBounds.height;
        }

        bounds.width = width;
        bounds.height = height;
    }

    public Rectangle getBounds()
    {
        return new Rectangle(bounds);
    }

    public MapLayer addLayer(MapLayer layer)
    {
        layers.add(layer);
        return layer;
    }

    public void addLayerAfter(MapLayer l, MapLayer after)
    {
        layers.add(layers.indexOf(after) + 1, l);
    }

    public void addLayer(int index, MapLayer layer)
    {
        layers.add(index, layer);
    }

    public void setLayer(int index, MapLayer layer)
    {
        layers.set(index, layer);
    }

    public void addAllLayers(Collection<MapLayer> layers)
    {
        this.layers.addAll(layers);
    }

    public MapLayer removeLayer(int index)
    {
        return layers.remove(index);
    }

    public void removeAllLayers()
    {
        layers.removeAllElements();
    }

    public Vector<MapLayer> getLayerVector()
    {
        return layers;
    }

    public void setLayerVector(Vector<MapLayer> layers)
    {
        this.layers = layers;
    }

    public void swapLayerUp(int index)
    {
        if (index + 1 == layers.size())
        {
            throw new RuntimeException(
                    "Can't swap up when already at the top.");
        }

        MapLayer hold = layers.get(index + 1);
        layers.set(index + 1, getLayer(index));
        layers.set(index, hold);
    }

    public void swapLayerDown(int index)
    {
        if (index - 1 < 0)
        {
            throw new RuntimeException(
                    "Can't swap down when already at the bottom");
        }

        MapLayer hold = layers.at(index - 1);
        layers.set(index - 1, getLayer(index));
        layers.set(index, hold);
    }

    public void mergeLayerDown(int index)
    {
        if (index - 1 < 0)
        {
            throw new RuntimeException("Can't merge down bottom layer.");
        }

        TileLayer ntl;
        try
        {
            ntl = (TileLayer)getLayer(index - 1).clone();
        }
        catch(CloneNotSupportedException e)
        {
            e.printStackTrack();
            return;
        }

        getLayer(index).mergeOnto(ntl);
        setLayer(index - 1, ntl);
        removeLayer(index);
    }

    public MapLayer getLayer(int i)
    {
        try
        {
            return layers.get(i);
        }
        catch(ArrayIndexOutOfBoundsException e)
        {
            
        }
        return null;
    }

    public ListIterator<MapLayer> getLayers()
    {
        return layers.listIterator();
    }

    public void resize(int width, int height, int dx, int dy)
    {
        ListIterator itr = getLayers();
        while(itr.hasNext())
        {
            MapLayer layer = (MapLayer)itr.next();
            if (layer.bounds.equals(bounds))
            {
                layer.resize(width, height, dx, dy);
            }
            else
            {
                layer.setOffset(layer.bounds.x + dx, layer.bounds.y + dy);
            }
        }

        bounds.width = width;
        bounds.height = height;
    }

    public boolean inBounds(int x, int y)
    {
        return x >= 0 && y >= 0 && x < bounds.width && y < bounds.height;
    }

    public Iterator<MapLayer> iterator()
    {
        return layers.iterator();
    }
}
